home *** CD-ROM | disk | FTP | other *** search
- #! /usr/bin/perl
- # -*-Perl-*-
- #
- #
- # Perl filter to handle pre-commit checking of files. This program
- # records the last directory where commits will be taking place for
- # use by the log_accum.pl script. For new files, it forces the
- # existence of a RCS "Id" keyword in the first ten lines of the file.
- # For existing files, it checks version number in the "Id" line to
- # prevent losing changes because an old version of a file was copied
- # into the direcory.
- #
- # Possible future enhancements:
- #
- # Check for cruft left by unresolved conflicts. Search for
- # "^<<<<<<<$", "^-------$", and "^>>>>>>>$".
- #
- # Look for a copyright and automagically update it to the
- # current year. [[ bad idea! -- woods ]]
- #
- #
- # Contributed by David Hampton <hampton@cisco.com>
- #
- # Hacked on lots by Greg A. Woods <woods@web.net>
-
- #
- # Configurable options
- #
-
- # Constants (remember to protect strings from RCS keyword substitution)
- #
- $LAST_FILE = "/tmp/#cvs.lastdir"; # must match name in log_accum.pl
- $ENTRIES = "CVS/Entries";
-
- # Patterns to find $Log keywords in files
- #
- $LogString1 = "\\\$\\Log: .* \\\$";
- $LogString2 = "\\\$\\Log\\\$";
- $NoLog = "%s - contains an RCS \$Log keyword. It must not!\n";
-
- # pattern to match an RCS Id keyword line with an existing ID
- #
- $IDstring = "\"@\\(#\\)[^:]*:.*\\\$\Id: .*\\\$\"";
- $NoId = "
- %s - Does not contain a properly formatted line with the keyword \"Id:\".
- I.e. no lines match \"" . $IDstring . "\".
- Please see the template files for an example.\n";
-
- # pattern to match an RCS Id keyword line for a new file (i.e. un-expanded)
- #
- $NewId = "\"@(#)[^:]*:.*\\$\Id\\$\"";
-
- $NoName = "
- %s - The ID line should contain only \"@(#)module/path:\$Name\$:\$\Id\$\"
- for a newly created file.\n";
-
- $BadName = "
- %s - The file name '%s' in the ID line does not match
- the actual filename.\n";
-
- $BadVersion = "
- %s - How dare you!!! You replaced your copy of the file '%s',
- which was based upon version %s, with an %s version based
- upon %s. Please move your '%s' out of the way, perform an
- update to get the current version, and them merge your changes
- into that file, then try the commit again.\n";
-
- #
- # Subroutines
- #
-
- sub write_line {
- local($filename, $line) = @_;
- open(FILE, ">$filename") || die("Cannot open $filename, stopped");
- print(FILE $line, "\n");
- close(FILE);
- }
-
- sub check_version {
- local($i, $id, $rname, $version);
- local($filename, $cvsversion) = @_;
-
- open(FILE, "<$filename") || return(0);
-
- @all_lines = ();
- $idpos = -1;
- $newidpos = -1;
- for ($i = 0; <FILE>; $i++) {
- chop;
- push(@all_lines, $_);
- if ($_ =~ /$IDstring/) {
- $idpos = $i;
- }
- if ($_ =~ /$NewId/) {
- $newidpos = $i;
- }
- }
-
- if (grep(/$LogString1/, @all_lines) || grep(/$LogString2/, @all_lines)) {
- print STDERR sprintf($NoLog, $filename);
- return(1);
- }
-
- if ($debug != 0) {
- print STDERR sprintf("file = %s, version = %d.\n", $filename, $cvsversion{$filename});
- }
-
- if ($cvsversion{$filename} == 0) {
- if ($newidpos != -1 && $all_lines[$newidpos] !~ /$NewId/) {
- print STDERR sprintf($NoName, $filename);
- return(1);
- }
- return(0);
- }
-
- if ($idpos == -1) {
- print STDERR sprintf($NoId, $filename);
- return(1);
- }
-
- $line = $all_lines[$idpos];
- $pos = index($line, "Id: ");
- if ($debug != 0) {
- print STDERR sprintf("%d in '%s'.\n", $pos, $line);
- }
- ($id, $rname, $version) = split(' ', substr($line, $pos));
- if ($rname ne "$filename,v") {
- print STDERR sprintf($BadName, $filename, substr($rname, 0, length($rname)-2));
- return(1);
- }
- if ($cvsversion{$filename} < $version) {
- print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},
- "newer", $version, $filename);
- return(1);
- }
- if ($cvsversion{$filename} > $version) {
- print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},
- "older", $version, $filename);
- return(1);
- }
- return(0);
- }
-
- #
- # Main Body
- #
-
- $id = getpgrp(); # You *must* use a shell that does setpgrp()!
-
- # Check each file (except dot files) for an RCS "Id" keyword.
- #
- $check_id = 0;
-
- # Record the directory for later use by the log_accumulate stript.
- #
- $record_directory = 0;
-
- # parse command line arguments
- #
- while (@ARGV) {
- $arg = shift @ARGV;
-
- if ($arg eq '-d') {
- $debug = 1;
- print STDERR "Debug turned on...\n";
- } elsif ($arg eq '-c') {
- $check_id = 1;
- } elsif ($arg eq '-r') {
- $record_directory = 1;
- } else {
- push(@files, $arg);
- }
- }
-
- $directory = shift @files;
-
- if ($debug != 0) {
- print STDERR "dir - ", $directory, "\n";
- print STDERR "files - ", join(":", @files), "\n";
- print STDERR "id - ", $id, "\n";
- }
-
- # Suck in the CVS/Entries file
- #
- open(ENTRIES, $ENTRIES) || die("Cannot open $ENTRIES.\n");
- while (<ENTRIES>) {
- local($filename, $version) = split('/', substr($_, 1));
- $cvsversion{$filename} = $version;
- }
-
- # Now check each file name passed in, except for dot files. Dot files
- # are considered to be administrative files by this script.
- #
- if ($check_id != 0) {
- $failed = 0;
- foreach $arg (@files) {
- if (index($arg, ".") == 0) {
- next;
- }
- $failed += &check_version($arg);
- }
- if ($failed) {
- print STDERR "\n";
- exit(1);
- }
- }
-
- # Record this directory as the last one checked. This will be used
- # by the log_accumulate script to determine when it is processing
- # the final directory of a multi-directory commit.
- #
- if ($record_directory != 0) {
- &write_line("$LAST_FILE.$id", $directory);
- }
- exit(0);
-